/*
 * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */

#ifndef BSD_KDEBUG_PRIVATE_H
#define BSD_KDEBUG_PRIVATE_H

#include <stdint.h>
#include <stdbool.h>
#include <sys/cdefs.h>
#include <sys/kdebug.h>

__BEGIN_DECLS

#if !KERNEL

#include <Availability.h>

#pragma mark - user space SPI

/*
 * OS components can use the full precision of the "code" field
 * (Class, SubClass, Code) to inject events using kdebug_trace() by
 * using:
 *
 * kdebug_trace(KDBG_CODE(DBG_XPC, 15, 1) | DBG_FUNC_NONE, 1, 2, 3, 4);
 *
 * These trace points can be included in production code, since they
 * use reserved, non-overlapping ranges.  The performance impact when
 * kernel tracing is not enabled is minimal.  However, when tracing is enabled,
 * each tracepoint becomes a syscall.  For this reason, os_signpost(3) is
 * recommended instead of kdebug_trace(2).
 *
 * Classes can be reserved by filing a Radar in xnu | ktrace.
 *
 * 64-bit arguments may be truncated if the system is using a 32-bit
 * kernel.
 *
 * On error, -1 will be returned and errno will indicate the error.
 */
int kdebug_trace(uint32_t code, uint64_t arg1, uint64_t arg2, uint64_t arg3,
    uint64_t arg4)
__OSX_AVAILABLE(10.10) __IOS_AVAILABLE(8.2);

/*!
 * @function kdebug_trace_string
 *
 * @discussion
 * This function emits strings to kdebug trace along with an ID and allows
 * for previously-traced strings to be overwritten and invalidated.
 *
 * To start tracing a string and generate an ID to use to refer to it:
 *
 *      string_id = kdebug_trace_string(debugid, 0, "string");
 *
 * To replace a string previously traced:
 *
 *      string_id = kdebug_trace_string(debugid, string_id, "new string");
 *
 * To invalidate a string ID:
 *
 *      string_id = kdebug_trace_string(debugid, string_id, NULL);
 *
 * To check for errors:
 *
 *      if ((int64_t)string_id == -1) { perror("string error") }
 *
 * @param debugid
 * The `debugid` to check if its enabled before tracing and include as
 * an argument in the event containing the string.
 *
 * Some classes or subclasses are reserved for specific uses and are not
 * allowed to be used with this function.  No function qualifiers are
 * allowed on `debugid`.
 *
 * @param str_id
 * When 0, a new ID will be generated and returned if tracing is
 * enabled.
 *
 * Otherwise `str_id` must contain an ID that was previously generated
 * with this function.  Clents should pass NULL in `str` if `str_id`
 * is no longer in use.  Otherwise, the string previously mapped to
 * `str_id` will be overwritten with the contents of `str`.
 *
 * @param str
 * A NUL-terminated 'C' string containing the characters that should be
 * traced alongside `str_id`.
 *
 * If necessary, the string will be truncated at an
 * implementation-defined length.  The string must not be the empty
 * string, but can be NULL if a valid `str_id` is provided.
 *
 * @return
 * 0 if tracing is disabled or `debugid` is being filtered out of trace.
 * It can also return (int64_t)-1 if an error occured. Otherwise,
 * it returns the ID to use to refer to the string in future
 * kdebug_trace(2) calls.
 *
 * The errors that can occur are:
 *
 * EINVAL
 *      There are function qualifiers on `debugid`, `str` is empty, or
 *      `str_id` was not generated by this function.
 * EPERM
 *      The `debugid`'s class or subclass is reserved for internal use.
 * EFAULT
 *      `str` is an invalid address or NULL when `str_id` is 0.
 */
extern uint64_t kdebug_trace_string(uint32_t debugid, uint64_t str_id,
    const char *str)
__OSX_AVAILABLE(10.11) __IOS_AVAILABLE(9.0);

/*
 * Although the performance impact of kdebug_trace() when kernel
 * tracing is not enabled is minimal, it may require the caller to
 * perform an expensive calculation/summarization. This cost can be
 * skipped by checking the kdebug_is_enabled() predicate:
 *
 * if (kdebug_is_enabled(KDBG_CODE(DBG_XPC, 15, 1))) {
 *     uint64_t arg1 = ...;
 *     uint64_t arg2 = ...;
 *     kdebug_trace(KDBG_CODE(DBG_XPC, 15, 1) | DBG_FUNC_NONE, arg1, arg2, 0, 0);
 * }
 *
 * If tracing is enabled for the code at the time of the check, 1
 * will be returned. Otherwise, 0 will be returned.
 */
extern bool kdebug_is_enabled(uint32_t code)
__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0)
__WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0);

/*
 * Returns a pointer to the userspace typefilter, if one is available.
 * May return NULL.
 */
extern void *kdebug_typefilter(void)
__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0)
__WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0);

/*
 * Returns true if kdebug is using continuous time for its events, and false
 * otherwise.
 */
extern bool kdebug_using_continuous_time(void)
__API_AVAILABLE(macos(10.15), ios(13), tvos(13), watchos(6));

#endif /* !KERNEL */

#pragma mark - private debugids

#define DBG_PPT         36
#define DBG_PERFCTRL    39
#define DBG_CLPC        50
#define DBG_MUSE        52

/* **** 128 to 139 are reserved for IOP tracing **** */
#define DBG_ANS         128
#define DBG_SIO         129
#define DBG_SEP         130
#define DBG_ISP         131
#define DBG_OSCAR       132
#define DBG_EMBEDDEDGFX 133
#define DBG_PMP         134
#define DBG_RTKIT       135

#define MACH_BRIDGE_RCV_TS      0x1     /* receive timestamp pair from interrupt handler */
#define MACH_BRIDGE_REMOTE_TIME 0x2     /* calculate remote timestamp */
#define MACH_BRIDGE_RESET_TS    0x3     /* reset timestamp conversion parameters */
#define MACH_BRIDGE_TS_PARAMS   0x4     /* recompute timestamp conversion parameters */
#define MACH_BRIDGE_SKIP_TS     0x5     /* skip timestamp */
#define MACH_BRIDGE_TS_MISMATCH 0x6     /* mismatch between predicted and received remote timestamp */
#define MACH_BRIDGE_OBSV_RATE   0x7     /* out of range observed rates */

/* DBG_SKYWALK has same toplevel code as DBG_DLIL, so don't reuse subcodes */
#define DBG_SKYWALK_ALWAYSON    0x10
#define DBG_SKYWALK_FLOWSWITCH  0x11
#define DBG_SKYWALK_NETIF       0x12
#define DBG_SKYWALK_CHANNEL     0x13
#define DBG_SKYWALK_PACKET      0x14

#define PPT_TEST            0x01
#define PPT_JETSAM_HIWAT    0x02
#define PPT_JETSAM_TOPPROC  0x03

#define SKYWALKDBG_CODE(SubClass, code) KDBG_CODE(DBG_DLIL, SubClass, code)
#define PPTDBG_CODE(SubClass, code) KDBG_CODE(DBG_PPT, SubClass, code)
#define PERFCTRL_CODE(SubClass, code) KDBG_CODE(DBG_PERFCTRL, SubClass, code)

#if !defined(DRIVERKIT)

extern unsigned int kdebug_enable;

/*
 * Bits used by kdebug_enable.  These control which events are traced at
 * runtime.
 */
#define KDEBUG_ENABLE_TRACE   (1U << 0)
#define KDEBUG_ENABLE_ENTROPY (1U << 1) /* obsolete */
#define KDEBUG_ENABLE_CHUD    (1U << 2) /* obsolete */
#define KDEBUG_ENABLE_PPT     (1U << 3) /* obsolete */
#define KDEBUG_ENABLE_SERIAL  (1U << 4) /* obsolete */

/*
 * If set, the timestamps in events are expected to be continuous times.
 * Otherwise, the timestamps are absolute times.  IOPs should observe this bit
 * in order to log events that can be merged cleanly with other event streams.
 */
#define KDEBUG_ENABLE_CONT_TIME 0x20

#define KDEBUG_TRACE (KDEBUG_ENABLE_TRACE)

/*
 * Specify KDEBUG_PPT to indicate that the event belongs to the limited PPT set.
 * PPT is deprecated -- use a typefilter and the PPTDBG class instead.
 */
#define KDEBUG_PPT    (KDEBUG_ENABLE_PPT)
#define KDEBUG_COMMON (KDEBUG_ENABLE_TRACE | KDEBUG_ENABLE_PPT)

/*
 * The kernel debug configuration level.  These values control which events are
 * compiled in under different build configurations.
 *
 * Infer the supported kernel debug event level from config option.  Use
 * (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD) as a guard to protect unaudited debug
 * code.
 */
#define KDEBUG_LEVEL_NONE     0
#define KDEBUG_LEVEL_IST      1
#define KDEBUG_LEVEL_STANDARD 2
#define KDEBUG_LEVEL_FULL     3

#if NO_KDEBUG
#define KDEBUG_LEVEL KDEBUG_LEVEL_NONE
#elif IST_KDEBUG
#define KDEBUG_LEVEL KDEBUG_LEVEL_IST
#elif KDEBUG
#define KDEBUG_LEVEL KDEBUG_LEVEL_FULL
#else
#define KDEBUG_LEVEL KDEBUG_LEVEL_STANDARD
/*
 * Currently, all other kernel configurations (development, etc) build with
 * KDEBUG_LEVEL_STANDARD.
 */
#endif

/*
 * Some Apple internal clients try to use the kernel macros in user space.
 */
#ifndef KERNEL_DEBUG
#define KERNEL_DEBUG(...) do { } while (0)
#endif /* !defined(KERNEL_DEBUG) */

#pragma mark - private definitions

/*
 * Ensure that both LP32 and LP64 variants of arm64 use the same kd_buf
 * structure.
 */
#if defined(__arm64__)
typedef uint64_t kd_buf_argtype;
#else
typedef uintptr_t kd_buf_argtype;
#endif

typedef struct {
	uint64_t timestamp;
	kd_buf_argtype arg1;
	kd_buf_argtype arg2;
	kd_buf_argtype arg3;
	kd_buf_argtype arg4;
	kd_buf_argtype arg5; /* the thread ID */
	uint32_t debugid;
/*
 * Ensure that both LP32 and LP64 variants of arm64 use the same kd_buf
 * structure.
 */
#if defined(__LP64__) || defined(__arm64__)
	uint32_t cpuid;
	kd_buf_argtype unused;
#endif
} kd_buf;

#if defined(__LP64__) || defined(__arm64__)
#define KDBG_TIMESTAMP_MASK             0xffffffffffffffffULL
static inline void
kdbg_set_cpu(kd_buf *kp, int cpu)
{
	kp->cpuid = (unsigned int)cpu;
}
static inline int
kdbg_get_cpu(kd_buf *kp)
{
	return (int)kp->cpuid;
}
static inline void
kdbg_set_timestamp(kd_buf *kp, uint64_t thetime)
{
	kp->timestamp = thetime;
}
static inline uint64_t
kdbg_get_timestamp(kd_buf *kp)
{
	return kp->timestamp;
}
static inline void
kdbg_set_timestamp_and_cpu(kd_buf *kp, uint64_t thetime, int cpu)
{
	kdbg_set_timestamp(kp, thetime);
	kdbg_set_cpu(kp, cpu);
}
#else
#define KDBG_TIMESTAMP_MASK 0x00ffffffffffffffULL
#define KDBG_CPU_MASK       0xff00000000000000ULL
#define KDBG_CPU_SHIFT      56
static inline void
kdbg_set_cpu(kd_buf *kp, int cpu)
{
	kp->timestamp = (kp->timestamp & KDBG_TIMESTAMP_MASK) |
	    (((uint64_t) cpu) << KDBG_CPU_SHIFT);
}
static inline int
kdbg_get_cpu(kd_buf *kp)
{
	return (int) (((kp)->timestamp & KDBG_CPU_MASK) >> KDBG_CPU_SHIFT);
}
static inline void
kdbg_set_timestamp(kd_buf *kp, uint64_t thetime)
{
	kp->timestamp = thetime & KDBG_TIMESTAMP_MASK;
}
static inline uint64_t
kdbg_get_timestamp(kd_buf *kp)
{
	return kp->timestamp & KDBG_TIMESTAMP_MASK;
}
static inline void
kdbg_set_timestamp_and_cpu(kd_buf *kp, uint64_t thetime, int cpu)
{
	kp->timestamp = (thetime & KDBG_TIMESTAMP_MASK) |
	    (((uint64_t) cpu) << KDBG_CPU_SHIFT);
}
#endif

/*
 * 2^16 bits (8 kilobytes), one for each possible class/subclass combination
 */
#define KDBG_TYPEFILTER_BITMAP_SIZE ((256 * 256) / 8)

/*
 * Bits for kd_ctrl_page.flags, KERN_KD{D,E}FLAGS.
 */
#define KDBG_INIT       (1U << 0) /* obsolete */
/* disable tracing when buffers are full */
#define KDBG_NOWRAP     (1U << 1)
#define KDBG_FREERUN    (1U << 2) /* obsolete */
/* buffer has wrapped */
#define KDBG_WRAPPED    (1U << 3)
/* flags that are allowed to be set by user space */
#define KDBG_USERFLAGS  (KDBG_FREERUN | KDBG_NOWRAP | KDBG_INIT)
/* only include processes with kdebug bit set in proc */
#define KDBG_PIDCHECK   (1U << 4)
/* thread map is initialized */
#define KDBG_MAPINIT    (1U << 5)
/* exclude processes based on kdebug bit in proc */
#define KDBG_PIDEXCLUDE (1U << 6)
/* whether the kdebug locks are intialized */
#define KDBG_LOCKINIT   (1U << 7)
/* word size of the kernel */
#define KDBG_LP64       (1U << 8)

/* bits for kd_ctrl_page.flags and kbufinfo_t.flags */

/* only trace events within a range */
#define KDBG_RANGECHECK       0x00100000U
/* only trace at most 4 types of events, at the code granularity */
#define KDBG_VALCHECK         0x00200000U
/* check class and subclass against the typefilter */
#define KDBG_TYPEFILTER_CHECK 0x00400000U
/* kdebug trace buffers are initialized */
#define KDBG_BUFINIT          0x80000000U

/* bits for the type field of kd_regtype */
#define KDBG_CLASSTYPE  0x10000
#define KDBG_SUBCLSTYPE 0x20000
#define KDBG_RANGETYPE  0x40000
#define KDBG_TYPENONE   0x80000
#define KDBG_CKTYPES    0xF0000

typedef struct {
	unsigned int type;
	unsigned int value1;
	unsigned int value2;
	unsigned int value3;
	unsigned int value4;
} kd_regtype;

typedef struct {
	/* number of events that can fit in the buffers */
	int nkdbufs;
	/* set if trace is disabled */
	int nolog;
	/* kd_ctrl_page.flags */
	unsigned int flags;
	/* number of threads in thread map */
	int nkdthreads;
	/* the owning pid */
	int bufid;
} kbufinfo_t;

typedef struct {
	/* the thread ID */
#if defined(__arm64__)
	uint64_t thread;
#else
	uintptr_t thread;
#endif
	/* 0 for invalid, otherwise the PID (or 1 for kernel_task) */
	int valid;
	/* the name of the process owning the thread */
	char command[20];
} kd_threadmap;

typedef struct {
	uint32_t version_no;
	uint32_t cpu_count;
} kd_cpumap_header;

/* cpumap flags */
#define KDBG_CPUMAP_IS_IOP      0x1

typedef struct {
	uint32_t cpu_id;
	uint32_t flags;
	char name[8];
} kd_cpumap;

typedef struct {
	int             version_no;
	int             thread_count;
	uint64_t        TOD_secs;
	uint32_t        TOD_usecs;
} RAW_header;

#define RAW_VERSION0    0x55aa0000
#define RAW_VERSION1    0x55aa0101
#define RAW_VERSION2    0x55aa0200 /* Only used by kperf and Instruments */

/*
 * Bits set in the comm page for kdebug.
 */
#define KDEBUG_COMMPAGE_ENABLE_TRACE      0x1
#define KDEBUG_COMMPAGE_ENABLE_TYPEFILTER 0x2 /* Forced to false if ENABLE_TRACE is 0 */

#pragma mark - EnergyTracing

/* for EnergyTracing user space & clients */
#define kEnTrCompKernel     2

/*
 *   EnergyTracing opcodes
 *
 *   Activations use DBG_FUNC_START/END.
 *   Events are DBG_FUNC_NONE.
 */

/* Socket reads and writes are uniquely identified by the (sanitized)
 *  pointer to the socket struct in question.  To associate this address
 *  with the user space file descriptor, we have a socket activation with
 *  the FD as its identifier and the socket struct pointer as its value.
 */
#define kEnTrActKernSocket      1
#define kEnTrActKernSockRead    2
#define kEnTrActKernSockWrite   3

#define kEnTrActKernPoll        10
#define kEnTrActKernSelect      11
#define kEnTrActKernKQWait      12

// events
#define kEnTrEvUnblocked        256

// EnergyTracing flags (the low-order 16 bits of 'quality')
#define kEnTrFlagNonBlocking    1 << 0
#define kEnTrFlagNoWork         1 << 1

/*
 * EnergyTracing macros.
 */

#if (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST)
// whether to bother calculating EnergyTracing inputs
// could change in future to see if DBG_ENERGYTRACE is active
#define ENTR_SHOULDTRACE kdebug_enable
// encode logical EnergyTracing into 32/64 KDebug trace
#define ENTR_KDTRACE(component, opcode, lifespan, id, quality, value)   \
do {                                                                    \
    uint32_t kdcode__;                                                  \
    uintptr_t highval__, lowval__, mask__ = 0xffffffff;                 \
    kdcode__ = KDBG_CODE(DBG_ENERGYTRACE,component,opcode)|(lifespan);  \
    highval__ = ((value) >> 32) & mask__;                               \
    lowval__ = (value) & mask__;                                        \
    ENTR_KDTRACEFUNC(kdcode__, id, quality, highval__, lowval__);       \
} while(0)

/*
 *   Trace the association of two existing activations.
 *
 *   An association is traced as a modification to the parent activation.
 *   In order to fit the sub-activation's component, activation code, and
 *   activation ID into a kdebug tracepoint, the arguments that would hold
 *   the value are left separate, and one stores the component and opcode
 *   of the sub-activation, while the other stores the pointer-sized
 *   activation ID.
 *
 *           arg2                   arg3               arg4
 +-----------------+  +~+----+----+--------+   +----------+
 |kEnTrModAssociate|  | |    |    |        |   |          |
 +-----------------+  +~+----+----+--------+   +----------+
 *                           8-bits unused       sub-activation ID
 *                                8-bit sub-component
 *                                     16-bit sub-opcode
 *
 */
#define kEnTrModAssociate (1 << 28)
#define ENTR_KDASSOCIATE(par_comp, par_opcode, par_act_id,              \
	    sub_comp, sub_opcode, sub_act_id)              \
do {                                                                    \
    unsigned sub_compcode = ((unsigned)sub_comp << 16) | sub_opcode;    \
    ENTR_KDTRACEFUNC(KDBG_CODE(DBG_ENERGYTRACE,par_comp,par_opcode),    \
	             par_act_id, kEnTrModAssociate, sub_compcode,       \
	             sub_act_id);                                       \
} while(0)

#else /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST) */

#define ENTR_SHOULDTRACE FALSE
#define ENTR_KDTRACE(component, opcode, lifespan, id, quality, value)   \
	                            do {} while (0)
#define ENTR_KDASSOCIATE(par_comp, par_opcode, par_act_id,              \
	    sub_comp, sub_opcode, sub_act_id)              \
	                            do {} while (0)

#endif /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST) */

#endif /* !defined(DRIVERKIT) */

__END_DECLS

#endif /* !defined(BSD_KDEBUG_PRIVATE_H) */
